/*******************************************************************************
Copyright (C), 200{x}, Borqs Tech. Co., Ltd.
File Name: 
    lapi_srv.c
Description: 
    LAPI server implementation   
History:  
    Date          Author                         Comments
    -----------   ---------------------------    --------------------
    Mar-19-2008   anle.zhou@borqs.com            Created
    May-23-2008   ray.fan@borqs.com              Add mechanism of Get Location timeout
    Jun-06-2008   ray.fan@borqs.com              Add member speed in LAPI_LOCATION_S struct
    Jun-23-2008   ray.fan@borqs.com              Ticket #731:AGPS/LBS: Settings - LAPI Client/Server Rework
*******************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <signal.h>
#include <ctype.h>
#include <dlfcn.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/select.h>
#include <sys/stat.h>
#include <sys/wait.h>


/*#include "utils/Log.h"
#undef LOG_TAG
#define LOG_TAG "LAPI_SRV"*/

#include <cutils/properties.h>

#include "lapi.h"
#include "lapi_ipc.h"
#include "lapi_comm.h"
#include "lapi_pid.h"
#include "lapi_setting.h"

//GPS Icon state of Status bar
//#define LAPI_ICON_DISABLE 0
//#define LAPI_ICON_ENABLE 1
#define LAPI_ICON_VISIBLE_UPDATE 1
#define LAPI_ICON_FIXING 2
#define LAPI_ICON_FIXED 3
#define LAPI_ICON_NO_FIXED 4
#define LAPI_SERVER_UNKNOWN 5
#define LAPI_SESSION_START 6
#define LAPI_SESSION_STOP 7

LAPI_CLIENT_S cltList[LAPI_CLIENT_MAX];
pthread_mutex_t op_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t close_mutex = PTHREAD_MUTEX_INITIALIZER;

const LAPI_LIB_Functions *lapiFuncs;

static LAPI_INT32 syncFd, asyncFd,lsnrFd;
static fd_set LAPI_ReadSet;
static LAPI_INT32 maxFd = 0;
static int clt_count = 0;
static int close_session_flag = 0;
static void *restartSessionThread(void *arg);
static LAPI_INT32 g_listener_fd = -1;
static int listens = 0;
/*
 * Current session type
 *
 * We support single session now, so we need this flag,
 * need protected by op_mutex
 *
 * 0 - unused
 * 1 - MO session
 * 2 - MT session
 *
 * a) When MOLR is ongoing, MTLR coming, should stop current
 * MOLR, after MTLR finish, start MOLR again
 *
 * b) When MTLR is ongoing, MOLR coming, should wait for MTLR complete
 *
 * c) Multi-MTLR will be serviced in sequence
 */
static int g_session_type = 0;
static int cmdFlag = 0;

static void cleanup_env()
{
    unlink(LAPI_SRV_SYNC_PATH);
    unlink(LAPI_SRV_ASYNC_PATH);
    unlink(LAPI_SRV_LISTENER_PATH);
}

static LAPI_INT32 LAPI_exec_command_new(int cmd)
{

    LAPI_INT8 msg;
    msg = 0;

    switch (cmd)
    {
        case LAPI_ICON_VISIBLE_UPDATE:
            msg = LAPI_UNSOLICITED_ICON_VISIBLE_UPDATE;
            break;
        case LAPI_ICON_FIXING:
            msg = LAPI_UNSOLICITED_ICON_FIXING;
            break;
        case LAPI_ICON_FIXED:
            msg = LAPI_UNSOLICITED_ICON_FIXED;
            break;
        case LAPI_ICON_NO_FIXED:
            msg = LAPI_UNSOLICITED_ICON_UNFIXED;
            break;
        case LAPI_SERVER_UNKNOWN:
            msg = LAPI_UNSOLICITED_CRITICAL_ERROR;
            break;
        case LAPI_SESSION_START:
            msg = LAPI_UNSOLICITED_SERVER_START;
            break;
        case LAPI_SESSION_STOP:
            msg = LAPI_UNSOLICITED_SERVER_CLOSE;
            break;
        default:
            return -1;
    }

    if(g_listener_fd != -1)
    LAPI_SendMsg(g_listener_fd, (LAPI_UINT8 *) &msg, sizeof(LAPI_INT8));

    /*To print the msg type number & string into log*/
    LAPI_INT8 *msgstr;
    msgstr = malloc(LAPI_MSGSTRING_LONG);
    memset(msgstr, 0, LAPI_MSGSTRING_LONG);
    LAPI_MSG_Handler(msg, msgstr);
    LAPI_DBG("<LAPI SERVER>Write to listener fd:%d, msg: %d: %s", g_listener_fd, msg, msgstr);
    free(msgstr);
	
    return 0;
}

static void LAPI_SigHandler(LAPI_INT32 sigNum)
{
    switch (sigNum)
    {
        case SIGPIPE:
            LAPI_DBG("<LAPI SERVER> LAPISRV received signal: SIGPIPE!");
            return;
        case SIGFPE:
            LAPI_DBG("<LAPI SERVER> LAPISRV received signal: SIGFPE!");
            break;
        case SIGTERM:
            // lapisrv stopped
            LAPI_DBG("<LAPI SERVER> LAPISRV received signal: SIGTERM!");
            char chipname[32];    /* chip detection */
            memset(chipname, 0, 32);
            property_get("hw.gps.chipset", chipname, NULL);
            if(0 != strcmp(chipname, "lapi_moto")) 
                lapiFuncs->onDisabled();
            break;
        case SIGSEGV:
            LAPI_DBG("<LAPI SERVER> LAPISRV received signal: SIGSEGV!");
            break;
        case SIGKILL:
            LAPI_DBG("<LAPI SERVER> LAPISRV received signal: SIGKILL!");
            break;
        default:
            LAPI_DBG("<LAPI SERVER> LAPISRV received signal: unknown %d!", sigNum);
            return;
    }

    //lapi_remove_pid();
    cleanup_env();
#ifdef LAPI_ON_ANDROID
    lapi_log_stop();
#endif
    exit(1);
}

static void LAPI_SetSignalHandler(void)
{
    struct sigaction saction;
    sigset_t smask;

    sigemptyset(&smask);
    saction.sa_handler = LAPI_SigHandler;
    saction.sa_mask = smask;
    saction.sa_flags = SA_SIGINFO;

    if (sigaction(SIGPIPE, &saction, (struct sigaction*)0) < 0)
    {
        LAPI_QUIT("Fail to sigaction SIGPIPE, errno is: %d, %s", errno, strerror(errno));
    }

    if (sigaction(SIGFPE, &saction, (struct sigaction*)0) < 0)
    {
        LAPI_QUIT("Fail to sigaction SIGFPE, errno is: %d, %s", errno, strerror(errno));
    }

    if (sigaction(SIGTERM, &saction, (struct sigaction*)0) < 0)
    {
        LAPI_QUIT("Fail to sigaction SIGTERM, errno is: %d, %s", errno, strerror(errno));
    }

    if (sigaction(SIGSEGV, &saction, (struct sigaction*)0) < 0)
    {
        LAPI_QUIT("Fail to sigaction SIGSEGV, errno is: %d, %s", errno, strerror(errno));
    }

    if (sigaction(SIGUSR1, &saction, (struct sigaction*)0) < 0)
    {
        LAPI_QUIT("Fail to sigaction SIGSEGV, errno is: %d, %s", errno, strerror(errno));
    }
}

static void print_lapi_client(LAPI_CLIENT_S clt) {
    LAPI_DBG("<LAPI SERVER> *** LAPI_CLIENT_S: %d, %d, %d, %d, %d", clt.sessionID,
            clt.syncFd, clt.asyncFd, clt.used, clt.type);
}

static int get_client_index(const LAPI_INT32 fd, LAPI_INT32 *num)
{
    LAPI_INT32 i, found = 0;
    int rslt = -1;

    pthread_mutex_lock(&op_mutex);
    for (i = 0; i < LAPI_CLIENT_MAX; i++)
    {
        if ((cltList[i].syncFd == fd) && (cltList[i].used == 1))
        {
            found = 1;
            break;
        }
    }

    if (found)
    {
        *num = i;
        rslt = 0;
    }
    pthread_mutex_unlock(&op_mutex);

    return rslt;
}

/*
 * check if all clients disconnect
 */
static int isAllClientClosed()
{
    int i;
    int flag = 0;

    //pthread_mutex_lock(&op_mutex);
    for (i = 0; i < LAPI_CLIENT_MAX; i++) {
        if (cltList[i].used == 1 ) {
            flag = 1;
            break;
        }
    }
    //pthread_mutex_unlock(&op_mutex);

    LAPI_exec_command_new(LAPI_ICON_VISIBLE_UPDATE);
	
    return !flag;
}

static void clear_client(const LAPI_UINT32 index)
{
    if (index > LAPI_CLIENT_MAX)
    {
        LAPI_ERR("<LAPI SERVER> Invalid index number");
        return;
    }

    pthread_mutex_lock(&op_mutex);
    cltList[index].sessionID = -1;
    cltList[index].syncFd = -1;
    cltList[index].asyncFd = -1;
    cltList[index].used = 0;
    cltList[index].type = LAPI_UNKNOWN_LISTENER;
    pthread_mutex_unlock(&op_mutex);

    return;
}

static LAPI_INT32 LAPI_Init_Server(void) {
    struct sockaddr_un addr;
    int i;

    cleanup_env();

    LAPI_SetSignalHandler();

    /* create socket */
    syncFd = socket(PF_LOCAL, SOCK_STREAM, 0);
    if (syncFd < 0) {
        LAPI_ERR("<LAPI SERVER> Failed to create sync socket");
        return -1;
    }
    asyncFd = socket(PF_LOCAL, SOCK_STREAM, 0);
    if (asyncFd < 0) {
        close(syncFd);
        LAPI_ERR("<LAPI SERVER> Failed to create async socket");
        return -1;
    }
    lsnrFd = socket(PF_LOCAL, SOCK_STREAM, 0);
    if (lsnrFd < 0) {
        close(lsnrFd);
        LAPI_ERR("<LAPI SERVER> Failed to create lsnrFd socket");
        return -1;
    }


    /* bind */
    memset(&addr, 0, sizeof(struct sockaddr_un));
    addr.sun_family = PF_LOCAL;
    strcpy(addr.sun_path, LAPI_SRV_SYNC_PATH);
    if (bind(syncFd, (struct sockaddr *) &addr, sizeof(struct sockaddr_un)) < 0) {
        LAPI_ERR("<LAPI SERVER> Failed to bind");
        close(syncFd);
        close(asyncFd);
        return -1;
    }
    memset(&addr, 0, sizeof(struct sockaddr_un));
    addr.sun_family = PF_LOCAL;
    strcpy(addr.sun_path, LAPI_SRV_ASYNC_PATH);
    if (bind(asyncFd, (struct sockaddr *) &addr, sizeof(struct sockaddr_un)) < 0) {
        LAPI_ERR("<LAPI SERVER> Failed to bind");
        close(syncFd);
        close(asyncFd);
        return -1;
    }
    memset(&addr, 0, sizeof(struct sockaddr_un));
    addr.sun_family = PF_LOCAL;
    strcpy(addr.sun_path, LAPI_SRV_LISTENER_PATH);
    if (bind(lsnrFd, (struct sockaddr *) &addr, sizeof(struct sockaddr_un)) < 0) {
        LAPI_ERR("<LAPI SERVER> Failed to bind");
        close(lsnrFd);
        return -1;
    }


    if (chmod(LAPI_SRV_SYNC_PATH, 0666) < 0) {
        LAPI_ERR("<LAPI SERVER> Failed to chmod %s", LAPI_SRV_SYNC_PATH);
        close(syncFd);
        close(asyncFd);
        return -1;
    }
    if (chmod(LAPI_SRV_ASYNC_PATH, 0666) < 0) {
        LAPI_ERR("<LAPI SERVER> Failed to chmod %s", LAPI_SRV_ASYNC_PATH);
        close(syncFd);
        close(asyncFd);
        return -1;
    }
    if (chmod(LAPI_SRV_LISTENER_PATH, 0666) < 0) {
        LAPI_ERR("<LAPI SERVER> Failed to chmod %s", LAPI_SRV_LISTENER_PATH);
        close(lsnrFd);
        return -1;
    }


    /* listen */
    if (listen(syncFd, LAPI_MAX_CONN) < 0) {
        LAPI_ERR("<LAPI SERVER> Failed to listen");
        close(syncFd);
        close(asyncFd);
        return -1;
    }
    if (listen(asyncFd, LAPI_MAX_CONN) < 0) {
        LAPI_ERR("<LAPI SERVER> Failed to listen");
        close(syncFd);
        close(asyncFd);
        return -1;
    }
    if (listen(lsnrFd, LAPI_MAX_CONN) < 0) {
        LAPI_ERR("<LAPI SERVER> Failed to listen");
        close(lsnrFd);
        return -1;
    }


    /* init client list */
    pthread_mutex_lock(&op_mutex);
    for (i = 0; i < LAPI_CLIENT_MAX; i++) {
        cltList[i].sessionID = -1;
        cltList[i].syncFd = -1;
        cltList[i].asyncFd = -1;
        cltList[i].used = 0;
        cltList[i].type = LAPI_UNKNOWN_LISTENER;
    }

    maxFd = LAPI_MAX(maxFd, syncFd);
    maxFd = LAPI_MAX(maxFd, asyncFd);
    maxFd = LAPI_MAX(maxFd, lsnrFd);

    FD_ZERO(&LAPI_ReadSet);
    FD_SET(syncFd, &LAPI_ReadSet);
    FD_SET(asyncFd, &LAPI_ReadSet);
    FD_SET(lsnrFd, &LAPI_ReadSet);
    pthread_mutex_unlock(&op_mutex);

    LAPI_DBG("<LAPI SERVER> LAPI Server Ready on sync: %d ; async: %d ; listener:%d", syncFd, asyncFd, lsnrFd);
    LAPI_DBG("<LAPI SERVER> maxFd is %d", maxFd);

    return 0;
}

/* handler new connection from sync FD */
static void NewSyncConnection(LAPI_INT32 syncFd)
{
    //LAPI_DBG("<LAPI SERVER> enter NewSyncConnection");
    LAPI_INT32 connFd;
    struct sockaddr_un addr;
    socklen_t addr_size;
    int i, found = 0;
    LAPI_MSG_RSP_S rsp;
    memset(&rsp, 0, sizeof(LAPI_MSG_RSP_S));

    addr_size = sizeof(struct sockaddr_un);
    connFd = accept(syncFd, (struct sockaddr *) &addr, &addr_size);
    if (connFd < 0) {
        LAPI_ERR("<LAPI SERVER> Failed to accept (%d - %s)", errno, strerror(errno));
        return;
    }

    pthread_mutex_lock(&op_mutex);
    for (i = 0; i < LAPI_CLIENT_MAX; i++) {
        if (cltList[i].used == 0) {
            found = 1;
            break;
        }
    }
    if (found) {
        cltList[i].syncFd = connFd;
        cltList[i].used = 1;
        FD_SET(connFd, &LAPI_ReadSet);
        maxFd = LAPI_MAX(maxFd, connFd);

        LAPI_DBG("<LAPI SERVER> Sync Client %d connected", connFd);
        LAPI_DBG("<LAPI SERVER> maxFd is %d", maxFd);
        LAPI_DBG("<LAPI SERVER> client list %d update", i);
    } else {
        LAPI_DBG("<LAPI SERVER> Session Full, Sync Client %d rejected", connFd);
        /*rsp.result = LAPI_RESULT_SESSION_FULL;
        LAPI_SendMsg(connFd, (LAPI_UINT8 *) &rsp, sizeof(LAPI_MSG_RSP_S));*/
        FD_CLR(connFd, &LAPI_ReadSet);
        close(connFd);
    }
    pthread_mutex_unlock(&op_mutex);
    //LAPI_DBG("<LAPI SERVER> leave NewSyncConnection");
}

/* handler new connection from async FD */
static void NewAsyncConnection(LAPI_INT32 asyncFd)
{
    //LAPI_DBG("<LAPI SERVER> enter NewAsyncConnection");
    LAPI_INT32 connFd;
    struct sockaddr_un addr;
    socklen_t addr_size;
    int i, found = 0;
    LAPI_INT32 flags;
    LAPI_MSG_RSP_S rsp;
    memset(&rsp, 0, sizeof(LAPI_MSG_RSP_S));

    addr_size = sizeof(struct sockaddr_un);
    connFd = accept(asyncFd, (struct sockaddr *) &addr, &addr_size);
    if (connFd < 0) {
        LAPI_ERR("<LAPI SERVER> Failed to accept (%d - %s)", errno, strerror(errno));
        return;
    }

    pthread_mutex_lock(&op_mutex);
    for (i = 0; i < LAPI_CLIENT_MAX; i++) {
        if ((cltList[i].used == 1) && (cltList[i].syncFd != -1)
            && (cltList[i].asyncFd == -1)) {
            found = 1;
            break;
        }
    }
    if (found) {
        cltList[i].asyncFd = connFd;
        FD_SET(connFd, &LAPI_ReadSet);
        maxFd = LAPI_MAX(maxFd, connFd);

        flags = fcntl(connFd, F_GETFL, 0);
        if (flags >= 0)
            fcntl(connFd, F_SETFL, (flags | O_NDELAY));

        LAPI_DBG("<LAPI SERVER> Async Client %d connected", connFd);
        LAPI_DBG("<LAPI SERVER> maxFd is %d", maxFd);
        LAPI_DBG("<LAPI SERVER> client list %d update", i);
    } else {
        LAPI_DBG("<LAPI SERVER> Session Full, Async Client %d rejected", connFd);
        /*rsp.result = LAPI_RESULT_SESSION_FULL;
        LAPI_SendMsg(connFd, (LAPI_UINT8 *) &rsp, sizeof(LAPI_MSG_RSP_S));*/
        FD_CLR(connFd, &LAPI_ReadSet);
        close(connFd);
    }
    pthread_mutex_unlock(&op_mutex);
    //LAPI_DBG("<LAPI SERVER> leave NewAsyncConnection");
}

static void NewListenerConnection(LAPI_INT32 fd)
{
    struct sockaddr_un addr;
    socklen_t addr_size;
    LAPI_INT32 flags;

    addr_size = sizeof(struct sockaddr_un);
    g_listener_fd = accept(fd, (struct sockaddr *) &addr, &addr_size);
    if (g_listener_fd < 0) {
        g_listener_fd = -1;
        LAPI_ERR("<LAPI SERVER> Failed to accept (%d - %s)", errno, strerror(errno));
        return;
    }
    LAPI_DBG("<LAPI SERVER> listener Client %d connected to update GPS icon", g_listener_fd);
    FD_SET(g_listener_fd, &LAPI_ReadSet); 
    maxFd = LAPI_MAX(maxFd, g_listener_fd);
    LAPI_DBG("<LAPI SERVER> maxFd is %d", maxFd);
    LAPI_DBG("<LAPI SERVER> -----LAPI SERVER IS READY TO WORK-----");
}
static void OpenSession(LAPI_INT32 fd)
{
    //LAPI_DBG("<LAPI SERVER> Get request LAPI_REQ_OPENSESSION");

    LAPI_MSG_RSP_S rsp;
    int i, found;

    memset(&rsp, 0, sizeof(LAPI_MSG_RSP_S));
    rsp.msgType = LAPI_RSP_OPENSESSION;

    pthread_mutex_lock(&op_mutex);
    for (i = 0; i < LAPI_CLIENT_MAX; i++) 
    {
        //print_lapi_client(cltList[i]);
        if ((cltList[i].syncFd == fd) && (cltList[i].used == 1)) 
        {
            found = 1;
            break;
        }
    }

    if (found) 
    {
        cltList[i].sessionID = i;
        rsp.sessionID = i;
        rsp.result = LAPI_RESULT_OK;
    }
    else
    {
        rsp.result = LAPI_RESULT_OPENSESSION_FAILED;
    }
    pthread_mutex_unlock(&op_mutex);

    LAPI_PrintRsp(&rsp);
    LAPI_SendMsg(fd, (LAPI_UINT8 *) &rsp, sizeof(LAPI_MSG_RSP_S));
}



static void StartSession(LAPI_INT32 fd, LAPI_INT32 sessionID, LAPI_MSG_TYPE_E type, LAPI_OTAMSG_S *msg)
{
    //LAPI_DBG("<LAPI SERVER> Get request start session, type is :%d", type);

    int i, found;
    LAPI_MSG_RSP_S rsp;
    LAPI_SESSION_TYPE s_type = LAPI_MO_SESSION;

    memset(&rsp, 0, sizeof(LAPI_MSG_RSP_S));
    rsp.sessionID = sessionID;
    if (LAPI_REQ_MO_STARTSESSION == type)
    {
        rsp.msgType = LAPI_RSP_MO_STARTSESSION;
        s_type = LAPI_MO_SESSION;
    } else if (LAPI_REQ_MT_STARTSESSION == type)
    {
        rsp.msgType = LAPI_RSP_MT_STARTSESSION;
        s_type = LAPI_MT_SESSION;
    }

    //send am broadcast let icon flicker
    LAPI_DBG("<LAPI SERVER> exec command : LAPI_ICON_FIXING");
    LAPI_exec_command_new(LAPI_ICON_FIXING);

    pthread_mutex_lock(&op_mutex);

    LAPI_DBG("<LAPI SERVER> *** clt_count = %d ***", clt_count);

    if (0 == clt_count) {
        /* NO clients */
        if (g_session_type == 0) {
            // unused
            if (s_type == LAPI_MO_SESSION)
            {
                g_session_type = 1;
            }
            else
            {
                cmdFlag = 0;
                g_session_type = 2;
            }
            LAPI_INF("<LAPI SERVER> No session, set g_session_type = %d", g_session_type);
        } /*else if (g_session_type == 1) {
            // MO session is running
            LAPI_INF("<LAPI SERVER> MO is running, s_type = %d", s_type);
            if (s_type == LAPI_MT_SESSION) {
                // TODO should stop current MOLR
                LAPI_INF("<LAPI SERVER> MO is running, stop MOLR, service MTLR first");
            }
        } else {
            // MT session is running
            LAPI_INF("<LAPI SERVER> MT is running, s_type = %d", s_type);
            if (s_type == LAPI_MT_SESSION) {
                // TODO should wait for previous complete
                LAPI_INF("<LAPI SERVER> MT is running, MTLR in queue");
            } else {
                // TODO should wait for previous complete
                LAPI_INF("<LAPI SERVER> MT is running, MOLR wait for MTLR complete");
            }
        }*/

        for (i = 0; i < LAPI_CLIENT_MAX; i++) {
            if ((cltList[i].syncFd == fd) && (cltList[i].used == 1)
                && (cltList[i].sessionID == sessionID)) {
                found = 1;
                break;
            }
        }

        if (found) {
            // reload settings
            lapi_load_setting();
            lapi_print_setting(); 
            if (g_debug_mode == 0)
            {
                // NO log build
                lapiFuncs->onInit(NULL, &g_lapi_setting, s_type, msg);
                LAPI_DBG("<LAPI SERVER> call onInit here, g_logger is NULL, session type is %d, ota message is %s", s_type, msg);
            }
            else
            {
                lapiFuncs->onInit(log_dispatcher, &g_lapi_setting, s_type, msg);
                LAPI_DBG("<LAPI SERVER> call onInit here, g)logger is not NULL, session type is %d, ota message is %s", s_type, msg);
            }
            // Call onStart immedieatlly if is MO session, for MT session should
            // call onStart after add SUPLInit listener
            if (s_type == LAPI_MO_SESSION){
                LAPI_DBG("<LAPI SERVER> Send LAPI_SESSION_START");
                LAPI_exec_command_new(LAPI_SESSION_START);
                lapiFuncs->onStart();
            }
            rsp.result = LAPI_RESULT_OK;
            clt_count++;
        } else {
            rsp.result = LAPI_RESULT_BAD_SESSIONID;
        }
    } else {
        int multi_flag = 1;
        if (g_session_type == 1) {
            // MO session is running
            LAPI_INF("<LAPI SERVER> MO is running, s_type = %d", s_type);
            if (s_type == LAPI_MT_SESSION) {
                // TODO should stop current MOLR, but we only can return fail by now
                LAPI_INF("<LAPI SERVER> MO is running, stop MOLR, service MTLR first");
                multi_flag = 0;
            }
        } else if (2 == g_session_type){
            // MT session is running
            LAPI_INF("<LAPI SERVER> MT is running, s_type = %d", s_type);
            if (s_type == LAPI_MT_SESSION) {
                // TODO should wait for previous complete, we return fail by now
                LAPI_INF("<LAPI SERVER> MT is running, MTLR in queue");
                multi_flag = 0;
            } else {
                // TODO should wait for previous complete
                LAPI_INF("<LAPI SERVER> MT is running, MOLR wait for MTLR complete");
                multi_flag = 0;
            }
        }
        else {
            LAPI_ERR("<LAPI SERVER> g_session_type: %d is incorrect", g_session_type);
        }

        if (multi_flag) {
            // some client already connected
            for (i = 0; i < LAPI_CLIENT_MAX; i++) {
                if ((cltList[i].syncFd == fd) && (cltList[i].used == 1)
                    && (cltList[i].sessionID == sessionID)) {
                    found = 1;
                    break;
                }
            }

            if (found) {
                clt_count++;
                LAPI_INF("<LAPI SERVER> >>> %d clients <<<", clt_count);
                rsp.result = LAPI_RESULT_OK;
            } else {
                rsp.result = LAPI_RESULT_BAD_SESSIONID;
            }
        } else {
            LAPI_INF("<LAPI SERVER> Not support multi MO/MT sessions!");
            rsp.result = LAPI_RESULT_BAD_REQ;
            // clt_count++ anyway, because in CloseSession always clt_count--
            clt_count++;
        }
    }

    pthread_mutex_unlock(&op_mutex);
    
    LAPI_PrintRsp(&rsp);
    LAPI_SendMsg(fd, (LAPI_UINT8 *) &rsp, sizeof(LAPI_MSG_RSP_S));
    return;
}

static void CloseSession(LAPI_INT32 fd, LAPI_INT32 sessionID)
{
    //LAPI_DBG("<LAPI SERVER> Get request LAPI_REQ_CLOSESESSION");

    LAPI_MSG_RSP_S rsp;
    int i, found;
    LAPI_INT32 fd2;

    memset(&rsp, 0, sizeof(LAPI_MSG_RSP_S));
    rsp.msgType = LAPI_RSP_CLOSESESSION;

    LAPI_DBG("<LAPI SERVER> ==== Try to lock op_mutex in function %s, line %d ====", __FUNCTION__, __LINE__);
    pthread_mutex_lock(&op_mutex);
    LAPI_DBG("<LAPI SERVER> ==== Locked op_mutex in function %s, line %d ====", __FUNCTION__, __LINE__);
    for (i = 0; i < LAPI_CLIENT_MAX; i++) {
        //print_lapi_client(cltList[i]);
        if ((cltList[i].syncFd == fd) && (cltList[i].used == 1)
            && (cltList[i].sessionID == sessionID)) {
            found = 1;
            break;
        }
    }
    if (found) {
        fd2 = cltList[i].asyncFd;
        cltList[i].sessionID = -1;
        cltList[i].syncFd = -1;
        cltList[i].asyncFd = -1;
        cltList[i].used = 0;
        cltList[i].type = LAPI_UNKNOWN_LISTENER;
        rsp.sessionID = -1;
    } else
        rsp.result = LAPI_RESULT_BAD_SESSIONID;

    clt_count--;
    clt_count = clt_count < 0 ? 0 : clt_count;

    LAPI_DBG("<LAPI SERVER> ### clt_count = %d ###", clt_count);

    if (isAllClientClosed() && found && (clt_count == 0)) {
        pthread_mutex_lock(&close_mutex);
        close_session_flag = 1;
        LAPI_DBG("<LAPI SERVER> ### set close_session_flag = 1 ###");
        lapiFuncs->onStop();
        LAPI_DBG("<LAPI SERVER> Send LAPI_SESSION_STOP");
        LAPI_exec_command_new(LAPI_SESSION_STOP);
        lapiFuncs->onExit();
        pthread_mutex_unlock(&close_mutex);

        if (2 == g_session_type)
        {
            cmdFlag = 0;
        }

        // only can clear g_session_type after all clients close
        g_session_type = 0;

        rsp.result = LAPI_RESULT_OK;

    }

    LAPI_DBG("<LAPI SERVER> ==== Try to unlock op_mutex in function %s, line %d ====", __FUNCTION__, __LINE__);
    pthread_mutex_unlock(&op_mutex);
    LAPI_DBG("<LAPI SERVER> ==== Unocked op_mutex in function %s, line %d ====", __FUNCTION__, __LINE__);
    pthread_mutex_lock(&close_mutex);
    close_session_flag = 0;
    LAPI_DBG("<LAPI SERVER> ### set close_session_flag = 0 ###");
    pthread_mutex_unlock(&close_mutex);

    LAPI_PrintRsp(&rsp);
    LAPI_SendMsg(fd, (LAPI_UINT8 *) &rsp, sizeof(LAPI_MSG_RSP_S));

    FD_CLR(fd, &LAPI_ReadSet);
    FD_CLR(fd2, &LAPI_ReadSet);
    close(fd);
    close(fd2);
}

/*static void *gprs_close(void *arg)
{
    int fd = *((int *) arg);

    LAPI_INF("<LAPI SERVER> sleep 10 let SUPL END");
    sleep(10);
    write(fd, "1\r\n", 1);
    LAPI_DBG("<LAPI SERVER> write GRPS_CLOSE to fd : %d", fd);

    return NULL;
}*/

static void myLocationListener(LAPI_LOCATION_S* fix, LAPI_LOCATION_STATUS status)
{
    int i;
    int ret;

    do {
        ret = pthread_mutex_trylock(&close_mutex);
        if (ret != 0) {
            usleep(1000*10);
            LAPI_DBG("<LAPI SERVER> pthread_mutex_trylock(&close_mutex) failed, try again... (%d - %d - %s)", ret, errno, strerror(errno));
        }
    } while (ret != 0 && (errno == EAGAIN || errno == EBUSY));

    LAPI_DBG("<LAPI SERVER> ### close_session_flag = %d ###", close_session_flag);
    if (1 == close_session_flag)
    {
        LAPI_DBG("<LAPI SERVER> ==== CloseSession is running, myLocationListener return here ====");
        pthread_mutex_unlock(&close_mutex);
        return;
    }
    pthread_mutex_unlock(&close_mutex);

    LAPI_INF("<LAPI SERVER> Got fix %p with status %d", fix, status);

    if (fix != NULL && status == LAPI_LOCATION_STATUS_VALID)
    {
        LAPI_INF("<LAPI SERVER> [Location] Lat:%f, Lon:%f, Alt:%f, TTFF:%d, TS:%lld",
                fix->latitude, fix->longitude, fix->altitude, fix->ttff, fix->timeStamp);

        //pthread_mutex_lock(&op_mutex);
        for (i = 0; i < LAPI_CLIENT_MAX; i++)
        {
            LAPI_UINT8 tmp = 0xFF;
            if ((cltList[i].syncFd != -1) \
                && (cltList[i].used == 1) \
                && (cltList[i].sessionID != -1) \
                && (cltList[i].asyncFd != -1) \
                //&& (cltList[i].type == LAPI_LOCATION_LISTENER))
                && ((cltList[i].type & LAPI_LOCATION_LISTENER) != 0))
            {
                write(cltList[i].asyncFd, fix, sizeof(LAPI_LOCATION_S));
                LAPI_DBG("<LAPI SERVER> write location fd : %d", cltList[i].asyncFd);
            }
#if 0
            //notify client to close network link if add LAPI_GPRSCLOSE_LISTENER
            else if ((cltList[i].syncFd != -1) \
                    && (cltList[i].used == 1) \
                    && (cltList[i].sessionID != -1) \
                    && (cltList[i].asyncFd != -1) \
                    && (cltList[i].type == LAPI_GPRSCLOSE_LISTENER))
            {
                pthread_t tid;

                pthread_create(&tid, NULL, gprs_close, (void *) &(cltList[i].asyncFd));
                /*LAPI_INF("<LAPI SERVER> sleep 30 let SUPL END");
                sleep(30);
                write(cltList[i].asyncFd, "1\r\n", 1);
                LAPI_DBG("<LAPI SERVER> write GRPS_CLOSE to fd : %d", cltList[i].asyncFd);*/
            }
#endif
        }
        //pthread_mutex_unlock(&op_mutex);
    } else if (status == LAPI_LOCATION_STATUS_END_NORMAL) {
        //pthread_mutex_lock(&op_mutex);
        if (2 == g_session_type)
        {
            for (i = 0; i < LAPI_CLIENT_MAX; i++)
            {
                //notify client to close network link if add LAPI_GPRSCLOSE_LISTENER
                if ((cltList[i].syncFd != -1) \
                        && (cltList[i].used == 1) \
                        && (cltList[i].sessionID != -1) \
                        && (cltList[i].asyncFd != -1) \
                        //&& (cltList[i].type == LAPI_GPRSCLOSE_LISTENER))
                        && ((cltList[i].type & LAPI_SUPLINIT_LISTENER) != 0))
                {
                    if (0 == cmdFlag)
                    {
                        //Let icon to get fix state
                        LAPI_DBG("<LAPI SERVER> exec command : LAPI_ICON_FIXED");
                        LAPI_exec_command_new(LAPI_ICON_FIXED);
                        cmdFlag = 1;
                    }
                }
            }
        }
        //pthread_mutex_unlock(&op_mutex);
    } else if (status == LAPI_LOCATION_STATUS_END_ABNORMAL) {
        //pthread_mutex_lock(&op_mutex);
        if (2 == g_session_type)
        {
            for (i = 0; i < LAPI_CLIENT_MAX; i++)
            
                //notify client to close network link if add LAPI_GPRSCLOSE_LISTENER
                if ((cltList[i].syncFd != -1) \
                        && (cltList[i].used == 1) \
                        && (cltList[i].sessionID != -1) \
                        && (cltList[i].asyncFd != -1) \
                        //&& (cltList[i].type == LAPI_GPRSCLOSE_LISTENER))
                        && ((cltList[i].type & LAPI_SUPLINIT_LISTENER) != 0))
                {
                    if (0 == cmdFlag)
                    {
                        //Let Icon to get no fix 
                        LAPI_DBG("<LAPI SERVER> exec command : LAPI_ICON_NO_FIXED");
                        LAPI_exec_command_new(LAPI_ICON_NO_FIXED);
                        cmdFlag = 1;
                    }
            }
        }
        //pthread_mutex_unlock(&op_mutex);
    } else if (status == LAPI_LOCATION_STATUS_UNKNOWN) {
        pthread_t tid_am_cmd;
        pthread_attr_t attr;
        pthread_attr_init(&attr);
        pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
        pthread_create(&tid_am_cmd, &attr, restartSessionThread, NULL);
    }
    LAPI_DBG("<LAPI SERVER> ==== myLocationListener exit ====");
}

static void myNMEAListener(LAPI_UINT8* message, LAPI_UINT16 length)
{
    int i;

    if (message == NULL || length <= 0)
        return;

    pthread_mutex_lock(&op_mutex);
    for (i = 0; i < LAPI_CLIENT_MAX; i++) {
        if ((cltList[i].syncFd != -1) \
            && (cltList[i].used == 1) \
            && (cltList[i].sessionID != -1) \
            && (cltList[i].asyncFd != -1) \
            //&& (cltList[i].type == LAPI_NMEA_LISTENER)) {
            && ((cltList[i].type & LAPI_NMEA_LISTENER) != 0)) {
            write(cltList[i].asyncFd, message, length);
            //LAPI_DBG("<LAPI SERVER> write NMEA fd : %d", cltList[i].asyncFd);
        }
    }
    pthread_mutex_unlock(&op_mutex);
}

static void *restartSessionThread(void *arg)
{
    LAPI_DBG("<LAPI SERVER> enter restartSessionThread thread ....");
    lapiFuncs->onStop();
    LAPI_DBG("<LAPI SERVER> Send LAPI_SESSION_STOP");
    LAPI_exec_command_new(LAPI_SESSION_STOP);
    lapiFuncs->onExit();
    lapiFuncs->onDisabled();
    lapi_load_setting();
    lapi_print_setting();
    if (g_session_type == 1)
    {
        if (g_debug_mode == 0)
        {
            lapiFuncs->onInit(NULL, &g_lapi_setting, LAPI_MO_SESSION, NULL);
        }
        else
        {
            lapiFuncs->onInit(log_dispatcher, &g_lapi_setting, LAPI_MO_SESSION, NULL);
        }

        lapiFuncs->onAddLocationListener(myLocationListener);
        lapiFuncs->onAddNMEAListener(myNMEAListener);
        LAPI_exec_command_new(LAPI_SESSION_START);
        lapiFuncs->onStart();
    }
    else
    {
        LAPI_DBG("<LAPI SERVER> Do not support MTLR restart");
    }

    return (void *)0;
}

static void mySUPLInitListener(LAPI_MTLR_USR_RSP* rsp)
{
    int i;
    //broadcast to client SUPLInit listener
    pthread_mutex_lock(&op_mutex);
    for (i = 0; i < LAPI_CLIENT_MAX; i++)
    {
        if ((cltList[i].syncFd != -1) \
            && (cltList[i].used == 1) \
            && (cltList[i].sessionID != -1) \
            && (cltList[i].asyncFd != -1) \
            //&& (cltList[i].type == LAPI_SUPLINIT_LISTENER))
            && ((cltList[i].type & LAPI_SUPLINIT_LISTENER) != 0))
        {
            write(cltList[i].asyncFd, (void *)rsp, sizeof(LAPI_MTLR_USR_RSP));
            LAPI_DBG("<LAPI SERVER> write SUPLInit listener fd : %d", cltList[i].asyncFd);
        }
    }
    pthread_mutex_unlock(&op_mutex);
}

static void MTVerification(LAPI_INT32 connFd, LAPI_INT32 sessionID, LAPI_MTLR_USR_ACTION action)
{
    //LAPI_DBG("<LAPI SERVER> Get request mtlr user verification, type is : %d", action);
    
    int i, found = 0;
    LAPI_MSG_RSP_S rsp;
    memset(&rsp, 0, sizeof(LAPI_MSG_RSP_S));
    rsp.sessionID = sessionID;

    if (LAPI_MTLR_ACCEPT == action)
    {
        rsp.msgType = LAPI_RSP_MT_VERIFICATION_ACCEPT;
    }
    else if (LAPI_MTLR_REJECT == action)
    {
        rsp.msgType = LAPI_RSP_MT_VERIFICATION_REJECT;
    }
    else if (LAPI_MTLR_IGNORE == action)
    {
        rsp.msgType = LAPI_RSP_MT_VERIFICATION_IGNORE;
    }

    rsp.result = LAPI_RESULT_UNKNOWN;

    pthread_mutex_lock(&op_mutex);
    for (i = 0; i < LAPI_CLIENT_MAX; i++)
    {
        if ((cltList[i].syncFd == connFd) && (cltList[i].used == 1)
            && (cltList[i].sessionID == sessionID))
        {
            found = 1;
            break;
        }
    }
    pthread_mutex_unlock(&op_mutex);

    if (!found)
    {
        LAPI_ERR("<LAPI SERVER> LAPI_REQ_MT_VERIFICATION: There is not match file descriptor and session ID");
        LAPI_PrintRsp(&rsp);
        LAPI_SendMsg(connFd, (LAPI_UINT8 *) &rsp, sizeof(LAPI_MSG_RSP_S));
        return;
    }

    lapiFuncs->onConfirmMTLR(action);

    rsp.result = LAPI_RESULT_OK;
    LAPI_PrintRsp(&rsp);
    LAPI_SendMsg(connFd, (LAPI_UINT8 *) &rsp, sizeof(LAPI_MSG_RSP_S));

    return;
}

static void AddListener(LAPI_INT32 connFd, LAPI_INT32 sessionID, LAPI_LISTENER_TYPE_E type)
{
    //LAPI_DBG("<LAPI SERVER> Requst add listener, type: %d", type);
    LAPI_MSG_RSP_S rsp;
    int i;

    memset(&rsp, 0, sizeof(LAPI_MSG_RSP_S));
    rsp.sessionID = sessionID;

    switch (type)
    {
        case LAPI_LOCATION_LISTENER:
            rsp.msgType = LAPI_RSP_ADD_LOCATIONLISTENER;
            break;
        case LAPI_NMEA_LISTENER:
            rsp.msgType = LAPI_RSP_ADD_NMEALISTENER;
            break;
        case LAPI_SUPLINIT_LISTENER:
            rsp.msgType = LAPI_RSP_ADD_SUPLINITLISTENER;
            break;
        case LAPI_GPRSCLOSE_LISTENER:
            rsp.msgType = LAPI_RSP_ADD_GPRSCLOSELISTENER;
            break;
        default:
            rsp.result = LAPI_RESULT_UNKNOWN;
            LAPI_SendMsg(connFd, (LAPI_UINT8 *) &rsp, sizeof(LAPI_MSG_RSP_S));
            return;
    }

    rsp.result = LAPI_RESULT_BAD_SESSIONID;

    pthread_mutex_lock(&op_mutex);
    for (i = 0; i < LAPI_CLIENT_MAX; i++)
    {
        //print_lapi_client(cltList[i]);
        if ((cltList[i].syncFd == connFd) \
           && (cltList[i].used == 1) \
           && (cltList[i].sessionID == sessionID) \
           && (cltList[i].asyncFd != -1))
        {
            /*
            if (cltList[i].type == LAPI_UNKNOWN_LISTENER)
            {
                cltList[i].type = type;        
                rsp.result = LAPI_RESULT_OK;
                LAPI_DBG("<LAPI SERVER> Add Listener : %d", type);
                break;
            }
            else
            {
                continue;
            }
            */
            cltList[i].type |= type;
            rsp.result = LAPI_RESULT_OK;
            LAPI_DBG("<LAPI SERVER> Add Listener : %d, cltList[%d].type : %d", type, i, cltList[i].type);
            break;
        }
    }
    pthread_mutex_unlock(&op_mutex);

    switch (type)
    {
        case LAPI_LOCATION_LISTENER:
            lapiFuncs->onAddLocationListener(myLocationListener);
            break;
        case LAPI_NMEA_LISTENER:
            lapiFuncs->onAddNMEAListener(myNMEAListener);
            break;
        case LAPI_SUPLINIT_LISTENER:
            lapiFuncs->onAddSUPLInitListener(mySUPLInitListener);
            lapiFuncs->onAddLocationListener(myLocationListener);
            LAPI_exec_command_new(LAPI_SESSION_START);
            lapiFuncs->onStart();
            break;
        case LAPI_GPRSCLOSE_LISTENER:
            break;
        default:
            break;
    }

    LAPI_PrintRsp(&rsp);
    LAPI_SendMsg(connFd, (LAPI_UINT8 *) &rsp, sizeof(LAPI_MSG_RSP_S));
    listens++;
}

static void RmListener(LAPI_INT32 connFd, LAPI_INT32 sessionID, LAPI_LISTENER_TYPE_E type)
{
    //LAPI_DBG("<LAPI SERVER> Requst remove listener %d", type);
    LAPI_MSG_RSP_S rsp;
    int i;

    memset(&rsp, 0, sizeof(LAPI_MSG_RSP_S));
    rsp.sessionID = sessionID;

    switch (type)
    {
        case LAPI_LOCATION_LISTENER:
            rsp.msgType = LAPI_RSP_RM_LOCATIONLISTENER;
            break;
        case LAPI_NMEA_LISTENER:
            rsp.msgType = LAPI_RSP_RM_NMEALISTENER;
            break;
        case LAPI_SUPLINIT_LISTENER:
            rsp.msgType = LAPI_RSP_RM_SUPLINITLISTENER;
            break;
        case LAPI_GPRSCLOSE_LISTENER:
            rsp.msgType = LAPI_RSP_RM_GPRSCLOSELISTENER;
            break;
        default:
            rsp.result = LAPI_RESULT_UNKNOWN;
            LAPI_SendMsg(connFd, (LAPI_UINT8 *) &rsp, sizeof(LAPI_MSG_RSP_S));
            return;
    }

    rsp.result = LAPI_RESULT_BAD_SESSIONID;

    pthread_mutex_lock(&op_mutex);
    for (i = 0; i < LAPI_CLIENT_MAX; i++)
    {
        //print_lapi_client(cltList[i]);
        if ((cltList[i].syncFd == connFd) \
            && (cltList[i].used == 1) \
            && (cltList[i].sessionID == sessionID) \
            && (cltList[i].asyncFd != -1) \
            && (cltList[i].type == type))
        {
            //cltList[i].type = LAPI_UNKNOWN_LISTENER;        
            LAPI_UINT8 tmp = ~type;
            cltList[i].type &= tmp;        
            rsp.result = LAPI_RESULT_OK;
            LAPI_DBG("<LAPI SERVER> Remove Listener : %d, cltList[%d].type : %d", type, i, cltList[i].type);
            break;
        }
    }
    pthread_mutex_unlock(&op_mutex);

    switch (type)
    {
        case LAPI_LOCATION_LISTENER:
            lapiFuncs->onRmLocationListener(myLocationListener);
            break;
        case LAPI_NMEA_LISTENER:
            lapiFuncs->onRmNMEAListener(myNMEAListener);
            break;
        case LAPI_SUPLINIT_LISTENER:
            lapiFuncs->onRmSUPLInitListener(mySUPLInitListener);
            break;
        case LAPI_GPRSCLOSE_LISTENER:
            break;
        default:
            break;
    }

    LAPI_PrintRsp(&rsp);
    LAPI_SendMsg(connFd, (LAPI_UINT8 *) &rsp, sizeof(LAPI_MSG_RSP_S));
    listens--;
    if(listens <= 0)
        LAPI_exec_command_new(LAPI_ICON_VISIBLE_UPDATE);
}

static void NewRequestForListener()
{
    LAPI_INT8 mes;
    mes = 0;
    int nread;
    nread = LAPI_RecvMsg(g_listener_fd, &mes);
    if(nread < 0)
        LAPI_ERR("<LAPI SERVER> Read Error in listener client");
    else if (nread == 0)
    {
        FD_CLR(g_listener_fd, &LAPI_ReadSet);
        close(g_listener_fd);
        g_listener_fd = -1;
        LAPI_DBG("<LAPI SERVER>clear listener fd: %d", g_listener_fd);
    }
}

/* dispatch incoming requests */
static void NewRequest(LAPI_INT32 connFd)
{
    //LAPI_DBG("<LAPI SERVER> enter NewRequest");
    int nread, index, i;
    LAPI_MSG_REQ_S req;
    LAPI_MSG_RSP_S rsp;

    memset(&req, 0, sizeof(LAPI_MSG_REQ_S));
    memset(&rsp, 0, sizeof(LAPI_MSG_RSP_S));

    nread = LAPI_RecvMsg(connFd, (LAPI_UINT8 *) &req);

    if (nread < 0)
        LAPI_ERR("<LAPI SERVER> Read error");
    else if (nread == 0)
    {
        if (get_client_index(connFd, &index) < 0)
        {
            LAPI_ERR("<LAPI SERVER> Can't find client index");
        }
        
        LAPI_INF("<LAPI SERVER> read 0, after close Errno:%d,%s",errno, strerror(errno));
        // Peer reset, should close sync/async FDs
        FD_CLR(connFd, &LAPI_ReadSet);
        close(connFd);
        LAPI_DBG("<LAPI SERVER>clear connFd: %d",connFd);
        
        for (i = 0; i < LAPI_CLIENT_MAX; i++)
        {
            if (cltList[i].syncFd == connFd) 
            {
                int connAFd = cltList[i].asyncFd;
                FD_CLR(connAFd, &LAPI_ReadSet);
                close(connAFd);
                LAPI_DBG("<LAPI SERVER>clear connAFd: %d",connAFd);
                break;
             }
        }
        if (i == LAPI_CLIENT_MAX)
        {
            LAPI_DBG("<LAPI SERVER> !!!It should NOT run into this log. Or else there's bug when operating cltList[] ");
        }

        clear_client(index);
        LAPI_DBG("<LAPI SERVER>clear index:%d",index);

        LAPI_DBG("<LAPI SERVER> Client %d-%d closed", connFd, (connFd+1));
        // If all client closed, should stop chipset
        if (isAllClientClosed()) {
            lapiFuncs->onStop();
            LAPI_DBG("<LAPI SERVER> Send LAPI_SESSION_STOP");
            LAPI_exec_command_new(LAPI_SESSION_STOP);
            lapiFuncs->onExit();
            g_session_type = 0;
            clt_count = 0; 
            // send am broadcast let icon stop flicker
            LAPI_DBG("<LAPI SERVER> exec command : LAPI_ICON_VISIBLE_UPDATE");
            LAPI_exec_command_new(LAPI_ICON_VISIBLE_UPDATE);
        }
    } else {
        LAPI_PrintReq(&req);
        switch (req.msgType) {
            case LAPI_REQ_OPENSESSION:
                OpenSession(connFd);
                break;
            case LAPI_REQ_MO_STARTSESSION:
                StartSession(connFd, req.sessionID, LAPI_REQ_MO_STARTSESSION, NULL);
                break;
            case LAPI_REQ_MT_STARTSESSION:
                StartSession(connFd, req.sessionID, LAPI_REQ_MT_STARTSESSION, (LAPI_OTAMSG_S *)req.data);
                break;
            case LAPI_REQ_CLOSESESSION:
                CloseSession(connFd, req.sessionID);
                break;
            case LAPI_REQ_GETLOCATION:
                break;
            case LAPI_REQ_ADD_LOCATIONLISTENER:
                AddListener(connFd, req.sessionID, LAPI_LOCATION_LISTENER);
                break;
            case LAPI_REQ_ADD_NMEALISTENER:
                AddListener(connFd, req.sessionID, LAPI_NMEA_LISTENER);
                break;
            case LAPI_REQ_ADD_SUPLINITLISTENER:
                AddListener(connFd, req.sessionID, LAPI_SUPLINIT_LISTENER);
                break;
            case LAPI_REQ_ADD_GPRSCLOSELISTENER:
                AddListener(connFd, req.sessionID, LAPI_GPRSCLOSE_LISTENER);
                break;
            case LAPI_REQ_RM_LOCATIONLISTENER:
                RmListener(connFd, req.sessionID, LAPI_LOCATION_LISTENER);
                break;
            case LAPI_REQ_RM_NMEALISTENER:
                RmListener(connFd, req.sessionID, LAPI_NMEA_LISTENER);
                break;
            case LAPI_REQ_RM_SUPLINITLISTENER:
                RmListener(connFd, req.sessionID, LAPI_SUPLINIT_LISTENER);
                break;
            case LAPI_REQ_RM_GPRSCLOSELISTENER:
                RmListener(connFd, req.sessionID, LAPI_GPRSCLOSE_LISTENER);
                break;
            case LAPI_REQ_MT_VERIFICATION_ACCEPT:
                MTVerification(connFd, req.sessionID, LAPI_MTLR_ACCEPT);
                break;
            case LAPI_REQ_MT_VERIFICATION_REJECT:
                MTVerification(connFd, req.sessionID, LAPI_MTLR_REJECT);
                break;
            case LAPI_REQ_MT_VERIFICATION_IGNORE:
                MTVerification(connFd, req.sessionID, LAPI_MTLR_IGNORE);
                break;
            default:
                rsp.sessionID = req.sessionID;
                rsp.msgType = req.msgType;
                rsp.result = LAPI_RESULT_BAD_REQ;
                LAPI_SendMsg(connFd, (LAPI_UINT8 *) &rsp, sizeof(LAPI_MSG_RSP_S));
                LAPI_ERR("<LAPI SERVER> Unknow request");
        }
    }
    //LAPI_DBG("<LAPI SERVER> leave NewRequest");
}

static void LAPI_INIT_FOR_RAM() 
{
    LAPI_DBG("<LAPI SERVER> Start to load onInit for RAM ");
    LAPI_INT32 retInit;
    if (g_debug_mode == 0)
    {
        // NO log build
        retInit = lapiFuncs->onInit(NULL, &g_lapi_setting, LAPI_MO_SESSION, NULL);
        LAPI_DBG("<LAPI SERVER> call onInit here, g_logger is NULL, session type is LAPI_MO_SESSION, ota message is NULL, just for download tracker");
    }
    else
    {
        retInit = lapiFuncs->onInit(log_dispatcher, &g_lapi_setting, LAPI_MO_SESSION, NULL);
        LAPI_DBG("<LAPI SERVER> call onInit here, g_logger is log_dispatcher, session type is LAPI_MO_SESSION, ota message is NULL, just for download tracker");
    }

    if(0 != retInit) {
        LAPI_ERR("<LAPI SERVER> LAPI Server failed to launch since failed to load onInit for RAM");

        cleanup_env();
#ifdef LAPI_ON_ANDROID
        lapi_log_stop();
#endif
        close(syncFd);
        close(asyncFd);
        exit(-1); 

    }
    LAPI_DBG("<LAPI SERVER> Load onInit successfully for RAM");
    lapiFuncs->onExit();
    LAPI_DBG("<LAPI SERVER> call onExit here, just for download tracker");
}

int main(int argc, char** argv)
{
    fd_set read_set;
    int ret;
    int i;
    void *dlHandle;
    char chipname[32];    /* chip detection */
    char gps_onoff[32];    /* GPS feature on/off */
    char agps_onoff[32];    /* A-GPS feature on/off */
    char libpath[32];
    int gps_flag, agps_flag = 0;

    const LAPI_LIB_Functions *(*lapiLoad)(void);

    /*if (lapi_pid_mutex() != 0)
    {
        fprintf(stderr, "Fail to pass lapi_pid_mutex()!");
        exit(1);
    }*/

#ifdef LAPI_ON_ANDROID
    lapi_log_start();
#endif

    LAPI_INF("<LAPI SERVER> lapisrv version = %s", LAPISRV_VERSION);

    /* make sure lapi.rc is here */
    lapi_load_setting();

    /* load shared library for different chipset */
    memset(chipname, 0, 32);
    memset(gps_onoff, 0, 32);
    memset(agps_onoff, 0, 32);
    memset(libpath, 0, 32);

    property_get("hw.gps.chipset", chipname, NULL);
    LAPI_INF("<LAPI SERVER> hw.gps.chipset = %s", chipname);
    sprintf(libpath, "lib%s.so", chipname);
    LAPI_INF("<LAPI SERVER> Try to load %s", libpath);

    property_get("hw.wireless.gps", gps_onoff, NULL);
    LAPI_INF("<LAPI SERVER> hw.wireless.gps = %s", gps_onoff);
    property_get("hw.wireless.gps.agps", agps_onoff, NULL);
    LAPI_INF("<LAPI SERVER> hw.wireless.gps.agps = %s", agps_onoff);

    if (!strcmp(gps_onoff, "true"))
        gps_flag = 1;

    if (!strcmp(agps_onoff, "true"))
        agps_flag = 1;

    dlHandle = dlopen(libpath, RTLD_NOW);
    if (dlHandle == NULL) {
        LAPI_ERR("<LAPI SERVER> dlopen failed: %s\n", dlerror());
        exit(-1);
    }

    lapiLoad = (const LAPI_LIB_Functions *(*)(void))dlsym(dlHandle, "LAPI_LIB_Load");

    if (lapiLoad == NULL) {
        LAPI_ERR("<LAPI SERVER> LAPI_LIB_Load not defined or exported in %s", libpath);
        exit(-1);
    }

    if (gps_flag == 0) {
        LAPI_ERR("<LAPI SERVER> GPS feature off, quit!");
        return -1;
    } else if (agps_flag == 0) {
        LAPI_INF("<LAPI SERVER> GPS only, no A-GPS!");
        if ((lapiLoad()->onInit == NULL) ||
            (lapiLoad()->onExit == NULL) ||
            (lapiLoad()->onStart == NULL) ||
            (lapiLoad()->onStop == NULL) ||
            (lapiLoad()->onAddLocationListener == NULL) ||
            (lapiLoad()->onRmLocationListener == NULL) ||
            (lapiLoad()->onAddNMEAListener == NULL) ||
            (lapiLoad()->onRmNMEAListener == NULL) ||
            (lapiLoad()->onDisabled == NULL)
           ) {
            LAPI_ERR("<LAPI SERVER> LAPI_LIB_Functions absent of GPS, quit!");
            return -1;
        }
    } else {
        LAPI_INF("<LAPI SERVER> GPS plus A-GPS!");
        if ((lapiLoad()->onAddSUPLInitListener == NULL) ||
            (lapiLoad()->onRmSUPLInitListener == NULL) ||
            (lapiLoad()->onConfirmMTLR == NULL)
           ) {
            LAPI_ERR("<LAPI SERVER> LAPI_LIB_Functions absent of A-GPS, quit!");
            return -1;
        }
    }

    lapiFuncs = lapiLoad();

    ret = LAPI_Init_Server();
    if (ret == -1) {
        LAPI_ERR("<LAPI SERVER> LAPI Server failed to launch");
        //lapi_remove_pid();
#ifdef LAPI_ON_ANDROID
        lapi_log_stop();
#endif
        return -1;
    }

    /*
     * For compatible 4t
     */
    if(0 == strcmp(libpath, "libgsd4t.so")) {
        LAPI_INIT_FOR_RAM();
    }

    while (1) {
        read_set = LAPI_ReadSet;

        ret = select(maxFd + 1, &read_set, NULL, NULL, NULL);
        if (ret < 0) {
            LAPI_ERR("<LAPI SERVER> Failed to select");
            return -1;
        }

        if (FD_ISSET(syncFd, &read_set)) {
            NewSyncConnection(syncFd);
            continue;
        }

        if (FD_ISSET(asyncFd, &read_set)) {
            NewAsyncConnection(asyncFd);
            continue;
        }

        if(FD_ISSET(lsnrFd, &read_set)){
            NewListenerConnection(lsnrFd);
            continue;
        }

        if(FD_ISSET(g_listener_fd, &read_set)){
            NewRequestForListener();
        }

        for (i = 0; i < LAPI_CLIENT_MAX; i++) {
            if ((cltList[i].syncFd != -1) && (cltList[i].used == 1)) {
                if (FD_ISSET(cltList[i].syncFd, &read_set))
                    NewRequest(cltList[i].syncFd);
            }
        }
    }

    close(syncFd);
    close(asyncFd);
    close(lsnrFd);

    cleanup_env();
    //lapi_remove_pid();
#ifdef LAPI_ON_ANDROID
    lapi_log_stop();
#endif

    return 0;
}
